// INCLUDES --------------------------------------------------------------------
#include "vertex.h"

// FUNCTIONS -------------------------------------------------------------------

/* GENERAL:
   d    -> destination
   s    -> source
   size -> array size (0,1 for single elements)

   a,b  -> two arbitrary vertices
   k    -> floating point scalar
*/

static int i;
static fp factor;

// clear to [0,0,0,1]
void vClear(vertex4 *v, ui32 size)
{
  GUARD_NULL("vClear *v", v);

  if (size == 0) size = 1;

  memset(v, 0, sizeof(vertex4)*size);
  for (i = 0; i < size; i++) v[i].w = 1.0f;
};

// clone vector src->dest
void vCopy(vertex4 *d, vertex4 *s, ui32 size)
{
  GUARD_NULL("vCopy *d", d);
  GUARD_NULL("vCopy *s", s);

  if (size == 0) size = 1;

  memcpy(d, s, sizeof(vertex4)*size);
};

/* the vector magnitude is defined by the pythagorean theorem for
   finding the length of a rectangular solid:

   |a| = sqrt(a² + b² + c²)

   which yields here to:

   |v| = sqrt(v.x² + v.y² + v.z²)

*/
fp vMagnitude(vertex4 *v)
{
  GUARD_NULL("vMagnitude *v", v);

  return sqrt(v->x*v->x +
              v->y*v->y +
              v->z*v->z);
};

/* a unit vector (denoted as â) is defined as the division of each of it's
   components by the vectors magnitude:

        a
   â = ---
       |a|

   so the result is basically:

        ax        ay        az
   âx = ---  ây = ---  âz = ---
        |a|       |a|       |a|

*/
void vNormalize(vertex4 *v)
{
  fp magnitude = vMagnitude(v);
  GUARD_ZERO("vNormalize magnitude", magnitude);

  factor = 1.0f / magnitude;
  vMulTo(v, magnitude);
};

/* inverse vector from a to -a. this is done by negating every component.
   thus we retrieve:

   -a = [-(x) -(y) -(z)]
*/
void vInvert(vertex4 *v) { vMulTo(v, -1.0f); };

/* the scalar product (also refered to as the "dot product") is the
   resulting scalar of the sum of the products of the individual
   vector components of a and b.

   it's defined as:

   a * b = ax * bx + ay * by + az * bz

*/
fp vScalarP(vertex4 *a, vertex4 *b)
{
  GUARD_NULL("vScalarP *a", a);
  GUARD_NULL("vScalarP *b", b);

  return (a->x * b->x +
          a->y * b->y +
          a->z * b->z);
};

/* the vector product is defined by the expansion of the matrix

             i   j   k
   a x b = | ax  ay  az | = c
           | bx  by  bz |

   which expands to:

   a x b = [ (ay * bz - az * by)i
            -(ax * bz - az * bx)j
             (ax * by - ay * bx)k ]

   the resulting vector c is perpendicular both to a and c.

*/
void vVectorP(vertex4 *d, vertex4 *a, vertex4 *b)
{
  GUARD_NULL("vVectorP *d", d);
  GUARD_NULL("vVectorP *a", a);
  GUARD_NULL("vVectorP *b", b);

  d->x =   a->y * b->z - a->z * b->y;
  d->y = -(a->x * b->z - a->z * b->x);
  d->z =   a->x * b->y - a->y * b->x;
};

// [+, +=] ---------------------------------------------------------------------
/* vector addition:

   vector addition is done by adding up each individual component of the vector a
   with the corresponding component of the second vector b.

   thus we retrieve:

   a + b = [ax+bx ay+by az+bz]

*/
void vAdd(vertex4 *d, vertex4 *a, vertex4 *b)
{
  GUARD_NULL("vAdd *d", d);
  GUARD_NULL("vAdd *a", a);
  GUARD_NULL("vAdd *b", b);

  d->x = a->x + b->x;
  d->y = a->y + b->y;
  d->z = a->z + b->z;
};

void vAddTo(vertex4 *d, vertex4 *a)
{
  GUARD_NULL("vAddTo *d", d);
  GUARD_NULL("vAddTo *a", a);

  d->x += a->x;
  d->y += a->y;
  d->z += a->z;
};

// [-, -=] ---------------------------------------------------------------------
/* vector subtraction:

   vector subtraction is done by subtracting each individual component
   of the vector a with the corresponding component of the second vector b.

   thus we retrieve:

   a - b = [ax-bx ay-by az-bz]

*/
void vSub(vertex4 *d, vertex4 *a, vertex4 *b)
{
  GUARD_NULL("vSub *d", d);
  GUARD_NULL("vSub *a", a);
  GUARD_NULL("vSub *b", b);

  d->x = a->x - b->x;
  d->y = a->y - b->y;
  d->z = a->z - b->z;
};

void vSubTo(vertex4 *d, vertex4 *a)
{
  GUARD_NULL("vSubTo *d", d);
  GUARD_NULL("vSubTo *a", a);

  d->x -= a->x;
  d->y -= a->y;
  d->z -= a->z;
};

// [*, *=] ---------------------------------------------------------------------
/* scalar multiplication:

   scalar multiplication is done by multiplicating each individual component
   of the vector a with the given scalar k.

   thus we retrieve:

   ka = [k*ax k*ay k*az]

*/
void vMul(vertex4 *d, vertex4* a, fp k)
{
  GUARD_NULL("vMul *d", d);
  GUARD_NULL("vMul *a", a);

  d->x = a->x * k;
  d->y = a->y * k;
  d->z = a->z * k;
};

void vMulTo(vertex4 *d, fp k)
{
  GUARD_NULL("vMulTo *d", d);

  d->x *= k;
  d->y *= k;
  d->z *= k;
};

// [/,/=] ---------------------------------------------------------------------
/* scalar division:

   scalar division is done by dividing each individual component
   of the vector a with the given scalar k.

   thus we retrieve:

   a / k = [ax/k ay/k az/k]

*/
void vDiv(vertex4 *d, vertex4* a, fp k)
{
  GUARD_ZERO("vDiv k", k);

  factor = 1.0f / k;
  vMul(d, a, factor);
};

void vDivTo(vertex4 *d, fp k)
{
  GUARD_ZERO("vDivTo k", k);

  factor = 1.0f / k;
  vMulTo(d, factor);
};

// [==,!=] --------------------------------------------------------------------
bool vEquals(vertex4 *a, vertex4 *b)
{
  GUARD_NULL("vEquals *a", a);
  GUARD_NULL("vEquals *b", b);

  return (a->x == b->x &&
          a->y == b->y &&
          a->z == b->z);
};

bool vInEquals(vertex4 *a, vertex4 *b) { return !vEquals(a, b); };
